/*
 * 
 */
package co.edu.udistrital.erpgrid.bd.modelo.connection;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import co.edu.udistrital.erpgrid.bd.modelo.connection.api.IFinder;
import co.edu.udistrital.erpgrid.exceptions.FinderException;

// TODO: Auto-generated Javadoc
/**
 * Base Finder para operaciones de consulta sobre entidades de negocio.
 * 
 */
@SuppressWarnings("unchecked")
@Repository
@Transactional
public class FinderImpl implements IFinder {

  /**
 * Manejador de Entidades.
 * @uml.property  name="entityManager"
 * @uml.associationEnd  readOnly="true" multiplicity="(0 -1)" elementType="org.hibernate.Session"
 */
  @PersistenceContext
  private transient EntityManager entityManager;

  /**
 * Maximo numero de resultados para ejecutar ciertas consultas.
 * @uml.property  name="maxResults"
 */
  private transient int maxResults;

  /** The Constant LOG. */
  private static final Logger LOG = LoggerFactory.getLogger(FinderImpl.class);

  /**
 * Asigna el valor de maximo numero de resultados para ejecutar ciertas consultas.
 * @param maxResults  maximo numero de resultados para ejecutar ciertas consultas
 * @uml.property  name="maxResults"
 */
  public void setMaxResults(int maxResults) {
    this.maxResults = maxResults;
  }

  /**
   * Constructor base.
   */
  public FinderImpl() {
    final int max = 500;
    maxResults = max;
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#getMaxResults()
   */
  
  public Integer getMaxResults() {
    return Integer.valueOf(this.maxResults);
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findAll(java.lang.Class)
   */
  
  public List findAll(Class entityType) throws FinderException {
    return findByCriteria(entityType, -1, this.maxResults);
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findById(java.io.Serializable, java.lang.Class)
   */
  
  public final Object findById(Serializable id, Class entityType) throws FinderException {
    try {
      Object o = entityManager.find(entityType, id);
//      LOG.info("BUSQUEDA con ID=" + id + "  ===> " + ReflectionToStringEntityBuilder.toString(o));
      return o;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findById(java.io.Serializable, java.lang.Class)
   */
  
  public final Object findById(Serializable id, Class entityType, boolean inicializar)
      throws FinderException {
    try {
      Object o = findById(id, entityType);
      if (inicializar)
        this.iniatialize(o);
//      LOG.info("BUSQUEDA con ID=" + id + "  ===> " + ReflectionToStringEntityBuilder.toString(o));
      return o;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findByCriteria(java.lang.Class,
   * org.hibernate.criterion.Criterion[])
   */
  
  public List findByCriteria(Class entityType, final Criterion... criterion) throws FinderException {
    LOG.debug("busqueda con criterios: " + criterion);
    List result = findByCriteria(entityType, -1, -1, criterion);
    StringBuffer buffer = new StringBuffer("BUSQUEDA   ===> LISTA {");
    for (Object object : result) {
//      buffer.append("\n\t[" + ReflectionToStringEntityBuilder.toString(object) + "]");
    }
    buffer.append("\n}");
    LOG.info(buffer.toString());
    return result;
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findByCriteria(java.lang.Class, int, int,
   * org.hibernate.criterion.Criterion[])
   */
  
  public final List findByCriteria(Class entityType, final int firstResult, final int maxResults,
      final Criterion... criterion) throws FinderException {
    try {
      Session session = (Session) entityManager.getDelegate();
      Criteria crit = session.createCriteria(entityType);
      for (final Criterion c : criterion) {
        if (c != null) {
          crit.add(c);
        }
      }
      if (firstResult > 0) {
        crit.setFirstResult(firstResult);
      }
      if (maxResults > 0) {
        crit.setMaxResults(maxResults);
      }
      return crit.list();
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findByCriteria(java.lang.Class, int, int,
   * java.lang.String[], org.hibernate.criterion.Criterion[])
   */
  
  public final List findByCriteria(Class entityType, final int firstResult, final int maxResults,
      final String[] alias, final Criterion... criterion) throws FinderException {
    try {
      Session session = (Session) entityManager.getDelegate();
      Criteria crit = session.createCriteria(entityType);
      for (final String t : alias) {
        if (t.trim().indexOf(' ') != -1) {
          String a[] = t.split(" ");
          crit.createAlias(a[0], a[1]);
        }
      }
      for (final Criterion c : criterion) {
        crit.add(c);
      }
      if (firstResult > 0) {
        crit.setFirstResult(firstResult);
      }
      if (maxResults > 0) {
        crit.setMaxResults(maxResults);
      }
      StringBuffer buffer = new StringBuffer("BUSQUEDA   ===> LISTA {");

      List result = crit.list();
      for (Object object : result) {
//        buffer.append("\n\t[" + ReflectionToStringEntityBuilder.toString(object) + "]");
      }
      buffer.append("\n}");
      LOG.info(buffer.toString());
      return result;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findByCriteria(java.lang.Class, int, int,
   * java.lang.String[], org.hibernate.criterion.Criterion[])
   */
  
  public final List findByCriteria(Class entityType, final int firstResult, final int maxResults,
      final String[] alias, boolean inicializar, final Criterion... criterion)
      throws FinderException {
    List lista = this.findByCriteria(entityType, firstResult, maxResults, alias, criterion);
    if (inicializar) {
      LOG.debug("INICIALIZANDO OBJETOS ....");
      for (Object obj : lista) {
        this.iniatialize(obj);
      }
    }
    return lista;
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findByNamedQuery(java.lang.String)
   */
  
  public List findByNamedQuery(String queryName) throws FinderException {
    try {
      Query query = entityManager.createNamedQuery(queryName);
      List result = query.getResultList();
      return result;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  
  /* (non-Javadoc)
   * @see co.edu.udistrital.erpgrid.bd.modelo.connection.api.IFinder#findByNamedQuery(java.lang.String, boolean)
   */
  public List findByNamedQuery(String queryName, boolean inicializar) throws FinderException {
    try {
      Query query = entityManager.createNamedQuery(queryName);
      List resultado = query.getResultList();
      if (inicializar) {
        LOG.debug("Inicializando objetos ...");
        for (Object obj : resultado) {
          this.iniatialize(obj);
        }
      }
      return resultado;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findByQuery(java.lang.String, java.lang.Object[])
   */
  
  public List findByQuery(String squery, Object... params) throws FinderException {
    try {
      Query query = entityManager.createQuery(squery);
      int i = 1;
      for (Object param : params) {
        if (param != null) {
          query.setParameter(i, param);
        }
        i++;
      }
      List result = query.getResultList();
      return result;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see co.gov.mme.mapper.dao.api.IFinder#findByNamedQuery(java.lang.String)
   */
  
  public List findByNamedQuery(String queryName, Object... params) throws FinderException {
    try {
      Query query = entityManager.createNamedQuery(queryName);//
      LOG.info("BUSQUEDA con query=" + queryName + "  : " + query.toString());
      if (params != null) {
        int i = 1;
        for (Object param : params) {
          if (param != null) {
            query.setParameter(i, param);
          }
          i++;
        }
      }
      List resultado = query.getResultList();
      StringBuffer buffer = new StringBuffer("FindByNamedQuery   ===> resultado {");

      for (Object object : resultado) {
//        buffer.append("\n\t[" + ReflectionToStringEntityBuilder.toString(object) + "]");
      }
      buffer.append("\n}");
      LOG.info(buffer.toString());
      return resultado;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  
  /* (non-Javadoc)
   * @see co.edu.udistrital.erpgrid.bd.modelo.connection.api.IFinder#findByNamedQuery(java.lang.String, boolean, java.lang.Object[])
   */
  public List findByNamedQuery(String queryName, boolean inicializar, Object... params)
      throws FinderException {
    try {
      Query query = entityManager.createNamedQuery(queryName);
      LOG.info("BUSQUEDA con query=" + queryName + "  : " + query.toString());
      if (params != null) {
        int i = 1;
        for (Object param : params) {
          if (param != null) {
            query.setParameter(i, param);
          }
          i++;
        }
      }
      List resultado = query.getResultList();
      if (inicializar) {
        LOG.debug("Inicializando objetos ...");
        for (Object obj : resultado) {
          this.iniatialize(obj);
        }
      }
      StringBuffer buffer = new StringBuffer("FindByNamedQuery   ===> resultado {");

      for (Object object : resultado) {
//        buffer.append("\n\t[" + ReflectionToStringEntityBuilder.toString(object) + "]");
      }
      buffer.append("\n}");
      LOG.info(buffer.toString());
      return resultado;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  /* (non-Javadoc)
   * @see co.edu.udistrital.erpgrid.bd.modelo.connection.api.IFinder#findByNativeQuery(java.lang.String, java.lang.Object[])
   */
  public List findByNativeQuery(String queryValue, Object... params) throws FinderException {
    try {
      Query query = entityManager.createNativeQuery(queryValue);

      if (params != null) {
        int i = 1;
        for (Object param : params) {
          if (param != null) {
            query.setParameter(i, param);
          }
          i++;
        }
      }
      List result = query.getResultList();
      return result;
    } catch (Exception e) {
      throw new FinderException(e);
    }
  }

  
  /* (non-Javadoc)
   * @see co.edu.udistrital.erpgrid.bd.modelo.connection.api.IFinder#executeNativeQuery(java.lang.String, java.lang.Object[])
   */
  public void executeNativeQuery(String queryValue, Object... params) throws FinderException {
    try {
      Query query = entityManager.createNativeQuery(queryValue);
      if (params != null) {
        int i = 1;
        for (Object param : params) {
          if (param != null) {
            query.setParameter(i, param);
          }
          i++;
        }
      }
      query.executeUpdate();
    } catch (Exception e) {
      throw new FinderException(e);
    }

  }

  /* (non-Javadoc)
   * @see co.edu.udistrital.erpgrid.bd.modelo.connection.api.IFinder#refresh(java.lang.Object)
   */
  public void refresh(Object o) {
    entityManager.refresh(o);
//    LOG.debug("entidad REFRESH " + ReflectionToStringBuilder.toString(o));

  }

  /* (non-Javadoc)
   * @see co.edu.udistrital.erpgrid.bd.modelo.connection.api.IFinder#iniatialize(java.lang.Object)
   */
  public void iniatialize(Object o) {
    Hibernate.initialize(o);
//    LOG.debug("entidad INITIALIZE " + ReflectionToStringBuilder.toString(o));
  }
}
